package adke.models;

import adke.gui.*;
import adke.gui.panels.GamePanel;
import adke.gui.panels.LinePanel;
import adke.managers.GameManager;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;

// we maken hier een speciale klasse voor omdat we de border
// dynamisch willen laten kunnen verplaatsen en verdikken

// verder neemt deze klasse de taak op zich alles uti te passen
// in verkleinde vensters

public class LinePanelBorder
{
    // houd dikte bij van individuele zijden
    private int[] THICKNESS;
    
    // houd offsets bij van individuele zijden
    private int[] OFFSET;
    
    // configuratie voor laatste wijziging:
    // [0] = THICKNESS, [1] = OFFSET
    private int[][] PREVIOUS;
    
    // orientatie
    public final static int ORIENTATION_LEFT =    0;
    public final static int ORIENTATION_RIGHT =   1;
    public final static int ORIENTATION_TOP =     2;
    public final static int ORIENTATION_BOTTOM =  3;
    
    // omdat er hier altijd maar een enkele van is kan hij static
    private static LinePanelBorder reference;
    
    // standaard instellingen
    public LinePanelBorder()
    {
        reference = this;
        
        // er passen diktes van 4 zijden in
        THICKNESS = new int[4];
        
        OFFSET = new int[4];
        
        PREVIOUS = new int[2][];
        
        toDefault();
    }
    
    public static LinePanelBorder getInstance()
    {
        return reference;
    }
    
    // TODO: overloaded constructors
    
    public boolean isEnabled()
    {
        return GameManager.isBorderEnabled();
    }
    
    public void toDefault()
    {
        // voordat we waarden veranderen moeten we ze backuppen
        backupConfig();
        
        for (int i = 0; i < 4; i++)
        {
            THICKNESS[i] = 1;
            
            // standaard offset van 32
            OFFSET[i] = 32;
            
            // als de border echter disabled is in het spel
            if (!GameManager.isBorderEnabled())
                OFFSET[i] = 0;
        }
    }
    
    private void backupConfig()
    {
        // voordat we waarden veranderen moeten we ze backuppen
        PREVIOUS[0] = THICKNESS;
        PREVIOUS[1] = OFFSET;
    }
    
    public synchronized void setThickness(int orientation, int thickness)
    {
        if (!GameManager.isBorderEnabled()) return;
        
        // voordat we waarden veranderen moeten we ze backuppen
        backupConfig();
        
        THICKNESS[orientation] = thickness;
        repaint();
    }
    
    public synchronized void setOffset(int orientation, int offset)
    {
        if (!GameManager.isBorderEnabled()) return;
        
        // voordat we waarden veranderen moeten we ze backuppen
        backupConfig();
        
        OFFSET[orientation] = offset;
        repaint();
    }
    
    public int getThickness(int orientation)
    {
        return THICKNESS[orientation];
    }
    
    public int getOffset(int orientation)
    {
        return OFFSET[orientation];
    }
    
    public int getHighestOffset()
    {
        int highest = 0;
        for (int offset : OFFSET)
        {
            if (offset > highest) highest = offset;
        }
        return highest;
    }
    
    // verkrijg lengte van een zijde
    public int getLength(int orientation)
    {
        int gameWidth = GamePanel.getInstance().getGameWidth();
        int gameHeight = GamePanel.getInstance().getGameHeight();
        
        // de zijden zijn in principe gelijk
        if (orientation == ORIENTATION_LEFT ||
                orientation == ORIENTATION_RIGHT)
        {
            return gameHeight - OFFSET[ORIENTATION_TOP] - OFFSET[ORIENTATION_BOTTOM];
        }
        
        // boven & onder
        else
        {
            return gameWidth - OFFSET[ORIENTATION_LEFT] - OFFSET[ORIENTATION_RIGHT];
        }
    }
    
    // als de border veranderd wordt moet de linepanel met zwart de oude border
    // over kunnen tekenen
    // we moeten dus de vorige coordinaten weten
    public int[][] getPreviousCoordinates()
    {
        return PREVIOUS;
    }
    
    public boolean pointWithinBorder(Point p)
    {
        int gw = GamePanel.getInstance().getGameWidth();
        int gh = GamePanel.getInstance().getGameHeight();
        
        // kijk of het punt binnen de border valt
        return  p.x > (OFFSET[ORIENTATION_LEFT]+THICKNESS[ORIENTATION_LEFT]) &&
                p.x < (gw - OFFSET[ORIENTATION_RIGHT] - THICKNESS[ORIENTATION_RIGHT]) &&
                p.y > (OFFSET[ORIENTATION_TOP]+THICKNESS[ORIENTATION_TOP]) &&
                p.y < (gh - OFFSET[ORIENTATION_BOTTOM] - THICKNESS[ORIENTATION_BOTTOM]);
    }
    
    // paint methoden
    
    // repaint zelf
    public void repaint()
    {
        // teken over de ouwe border heen
        clearBorder();
        
        // teken de nieuwe
        paint();
        
        LinePanel.getInstance().cleanRepaint();
    }
    
    public void clearBorder()
    {
        Graphics drawerGraphics = LinePanel.getInstance().getPanelGraphics();
        
        // TODO: als we borders hebben die al kunnen schuiven
        // moeten we de onderliggende laag tekenen, en niet zwart
        drawerGraphics.setColor(Color.BLACK);
        
        
        // clear eerst de TOP lijn
        int thick = PREVIOUS[0][ORIENTATION_TOP];   // dikte
        int x = PREVIOUS[1][ORIENTATION_LEFT];      // waar de lijn begint van links
        int y = PREVIOUS[1][ORIENTATION_TOP];       // waar de lijn begint van boven
        int w = GamePanel.getInstance().getGameWidth() -    // hoe breed de lijn is
                x - PREVIOUS[1][ORIENTATION_RIGHT];
        
        // clear nu
        drawerGraphics.fillRect(x, y, w, thick);
        
        
        
        // clear eerst de BOTTOM lijn
        thick = PREVIOUS[0][ORIENTATION_BOTTOM];   // dikte
        y = PREVIOUS[1][ORIENTATION_BOTTOM];       // waar de lijn begint van onder
        // de y is nu de afstand tot de rand. wat we moeten weten is de afstand tot de 
        // binnenste rand
        y = y - thick;
                
        // clear nu
        drawerGraphics.fillRect(x, y, w, thick);
        
        
        
        // clear eerst de LEFT lijn
        thick = PREVIOUS[0][ORIENTATION_LEFT];   // dikte
        x = PREVIOUS[1][ORIENTATION_LEFT];      // waar de lijn begint van links
        y = PREVIOUS[1][ORIENTATION_TOP];       // waar de lijn begint van boven
        int h = GamePanel.getInstance().getGameHeight()  // hoe hoog de lijn is
                - y - PREVIOUS[1][ORIENTATION_BOTTOM];
        
        // clear nu
        drawerGraphics.fillRect(x, y, thick, h);
        
        
        
        // clear eerst de RIGHT lijn
        thick = PREVIOUS[0][ORIENTATION_RIGHT];   // dikte
        x = PREVIOUS[1][ORIENTATION_RIGHT]-thick;      // waar de lijn begint van links
        
        // clear nu
        drawerGraphics.fillRect(x, y, thick, h);
    }
    
    public void paint()
    {
        Graphics drawerGraphics = LinePanel.getInstance().getPanelGraphics();
        
        drawerGraphics.setColor(Color.GRAY);
        
        
        // eerst de TOP lijn
        int thick = THICKNESS[ORIENTATION_TOP];   // dikte
        int x = OFFSET[ORIENTATION_LEFT];      // waar de lijn begint van links
        int y = OFFSET[ORIENTATION_TOP];       // waar de lijn begint van boven
        int w = getLength(ORIENTATION_BOTTOM);
        
        // clear nu
        drawerGraphics.fillRect(x, y, w, thick);
        
        
        
        // clear eerst de BOTTOM lijn
        thick = THICKNESS[ORIENTATION_BOTTOM];   // dikte
        y = OFFSET[ORIENTATION_BOTTOM];       // waar de lijn begint van onder
        // de y is nu de afstand tot de rand. wat we moeten weten is de afstand tot de 
        // binnenste rand
        y = GamePanel.getInstance().getGameHeight() - y - thick;
        
        // als we in fullscreen spelen hoeven we er geen rekening mee te houden
        //if (!Overview.getInstance().isFullscreen()) y = y - 40;
        
        // clear nu
        drawerGraphics.fillRect(x, y, w, thick);
        
        
        
        // clear eerst de LEFT lijn
        thick = THICKNESS[ORIENTATION_LEFT];   // dikte
        x = OFFSET[ORIENTATION_LEFT];      // waar de lijn begint van links
        y = OFFSET[ORIENTATION_TOP];       // waar de lijn begint van boven
        
        // getlength houd al rekening met titelbar compensatie
        int h = getLength(ORIENTATION_LEFT);
        
        // clear nu
        drawerGraphics.fillRect(x, y, thick, h);
        
        
        
        // clear eerst de RIGHT lijn
        thick = THICKNESS[ORIENTATION_RIGHT];   // dikte
        x = OFFSET[ORIENTATION_RIGHT]-thick+getLength(ORIENTATION_TOP);      // waar de lijn begint van links
        
        // clear nu
        drawerGraphics.fillRect(x, y, thick, h);
    }
}
